﻿#include "Drawer.h"

#include <glm/gtc/type_ptr.hpp>

Sector Drawer::initSector(size_t width, size_t height, double startAngle, double endAngle, double lightExtension,
                          unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
    Sector sector;
    sector.width = width;
    sector.height = height;
    sector.maxRadius = sqrt(width * width + height * height) / 2.0f;
    sector.centerX = width / 2.0f;
    sector.centerY = height / 2.0f;

    double extension = lightExtension;

    double angleDiff = endAngle - startAngle;
    extension = std::min(extension + angleDiff / 2, M_PI) - angleDiff / 2;
    angleDiff += 2 * extension;
    startAngle -= extension;
    endAngle += extension;

    // Generate vertex data (relative to center)
    std::vector<float> vertices;
    const float colorCenter[4] = {r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f};

    // Center vertex (dx, dy = 0)

    // const float lengthStep = 1.5f;
    // const double xUnit0 = std::cos(startAngle);
    // const double yUnit0 = -std::sin(startAngle);
    // for (float length = lengthStep; length < sector.maxRadius; length += lengthStep) {
    //     vertices.insert(vertices.end(), {
    //                         (float) (xUnit0 * length), (float) (yUnit0 * length), colorCenter[0], colorCenter[1],
    //                         colorCenter[2], 0.0f
    //                     });
    // }
    //
    // // Edge vertices
    // const float angleStep = 0.01f;
    // for (float angle = startAngle; angle <= endAngle; angle += angleStep) {
    //     const float dx = sector.maxRadius * std::cos(angle);
    //     const float dy = -sector.maxRadius * std::sin(angle);
    //     vertices.insert(vertices.end(), {dx, dy, colorCenter[0], colorCenter[1], colorCenter[2], 0.0f});
    //     // vertices.insert(vertices.end(), { dx, dy, 0.0f, 0.0f, 0.0f, 0.0f });
    // }
    // const double xUnit1 = std::cos(endAngle);
    // const double yUnit1 = -std::sin(endAngle);
    // for (float length = sector.maxRadius - lengthStep; length > 0; length -= lengthStep) {
    //     vertices.insert(vertices.end(), {
    //                         (float) (xUnit1 * length), (float) (yUnit1 * length), colorCenter[0], colorCenter[1],
    //                         colorCenter[2], 0.0f
    //                     });
    // }
    const int nRadial = 32;
    const int nAngular = 513;
    const int angularBisector = (nAngular - 1) / 2;
    for (int radiusN = nRadial; radiusN > 0; radiusN--) {
        const float radialFactor0 = 1.0f - (float)radiusN / nRadial;
        const float radius0 = sector.maxRadius * radiusN / nRadial;
        const float radialFactor1 = 1.0f - (float)(radiusN - 1) / nRadial;
        const float radius1 = sector.maxRadius * (radiusN - 1) / nRadial;
        for (int angleN = 0; angleN < nAngular - 1; angleN++) {
            const auto angle0 = (float)(angleDiff * angleN / nAngular + startAngle);
            const float x00 = std::cos(angle0) * radius0;
            const float y00 = -std::sin(angle0) * radius0;
            const float angularFactor0 = 1.0f - (float)std::abs(angleN - angularBisector) / angularBisector;
            const float x01 = std::cos(angle0) * radius1;
            const float y01 = -std::sin(angle0) * radius1;
            const auto angle1 = (float)(angleDiff * (angleN + 1) / nAngular + startAngle);
            const float x10 = std::cos(angle1) * radius0;
            const float y10 = -std::sin(angle1) * radius0;
            const float angularFactor1 = 1.0f - (float)std::abs(angleN + 1 - angularBisector) / angularBisector;
            const float x11 = std::cos(angle1) * radius1;
            const float y11 = -std::sin(angle1) * radius1;
            vertices.insert(vertices.end(), {x00, y00, colorCenter[0], colorCenter[1], colorCenter[2], colorCenter[3] * radialFactor0 * angularFactor0});
            vertices.insert(vertices.end(), {x01, y01, colorCenter[0], colorCenter[1], colorCenter[2], colorCenter[3] * radialFactor1 * angularFactor0});
            vertices.insert(vertices.end(), {x10, y10, colorCenter[0], colorCenter[1], colorCenter[2], colorCenter[3] * radialFactor0 * angularFactor1});
            vertices.insert(vertices.end(), {x11, y11, colorCenter[0], colorCenter[1], colorCenter[2], colorCenter[3] * radialFactor1 * angularFactor1});
            vertices.insert(vertices.end(), {x01, y01, colorCenter[0], colorCenter[1], colorCenter[2], colorCenter[3] * radialFactor1 * angularFactor0});
            vertices.insert(vertices.end(), {x10, y10, colorCenter[0], colorCenter[1], colorCenter[2], colorCenter[3] * radialFactor0 * angularFactor1});
        }
    }

    sector.vertexCount = vertices.size() / 6;

    // Create VBO/VAO
    glGenBuffers(1, &sector.vbo);
    glBindBuffer(GL_ARRAY_BUFFER, sector.vbo);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW);

    glGenVertexArrays(1, &sector.vao);
    glBindVertexArray(sector.vao);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *) (2 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // Create FBO resources
    glGenTextures(1, &sector.tempTex);
    glBindTexture(GL_TEXTURE_2D, sector.tempTex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glGenFramebuffers(1, &sector.tempFbo);
    glBindFramebuffer(GL_FRAMEBUFFER, sector.tempFbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sector.tempTex, 0);

    // 修改点1：将RBO替换为多采样纹理
    glGenTextures(1, &sector.colorTex);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, sector.colorTex);
    glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 1, GL_RGBA8, width, height, GL_TRUE);

    glGenFramebuffers(1, &sector.msaaFbo);
    glBindFramebuffer(GL_FRAMEBUFFER, sector.msaaFbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, sector.colorTex, 0);

    glGenFramebuffers(1, &sector.resolveFbo);
    glGenTextures(1, &sector.resolveTex);
    glBindTexture(GL_TEXTURE_2D, sector.resolveTex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glBindFramebuffer(GL_FRAMEBUFFER, sector.resolveFbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sector.resolveTex, 0);

    // 修改点2：深度附件仍然使用RBO（通常深度纹理需要更多处理）
    GLuint depthRbo;
    glGenRenderbuffers(1, &depthRbo);
    glBindRenderbuffer(GL_RENDERBUFFER, depthRbo);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRbo);

    sector.depthRbo = depthRbo;

    return sector;
}

void Drawer::drawSector(GLuint shaderProgram, Sector sector, size_t radius) {
    // 修改点3：移除错误的FBO绑定
    // glBlendEquation(GL_FUNC_ADD);

    // 首先绘制到临时FBO
    glBindFramebuffer(GL_FRAMEBUFFER, sector.tempFbo);
    glClear(GL_COLOR_BUFFER_BIT);

    // 正确的blit流程
    glBindFramebuffer(GL_READ_FRAMEBUFFER, sector.tempFbo);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, sector.msaaFbo);
    glBlitFramebuffer(0, 0, sector.width, sector.height,
                      0, 0, sector.width, sector.height,
                      GL_COLOR_BUFFER_BIT, GL_NEAREST);

    // 绘制到MSAA FBO
    glBindFramebuffer(GL_FRAMEBUFFER, sector.msaaFbo);
    glViewport(0, 0, sector.width, sector.height);

    static GLint locViewport = -1;
    static GLint locCenter = -1;
    static GLint locScale = -1;

    if (locViewport == -1) {
        locViewport = glGetUniformLocation(shaderProgram, "viewportSize");
        locCenter = glGetUniformLocation(shaderProgram, "center");
        locScale = glGetUniformLocation(shaderProgram, "scale");

        if (locViewport == -1 || locCenter == -1 || locScale == -1) {
            throw "Shader uniforms not found";
        }
    }

    glUseProgram(shaderProgram);
    float actualScale = std::clamp(radius / sector.maxRadius, 0.0f, 1.0f);

    glUniform2f(locViewport, sector.width, sector.height);
    glUniform2f(locCenter, sector.centerX, sector.centerY);
    glUniform1f(locScale, actualScale);

    glBindVertexArray(sector.vao);
    glEnable(GL_MULTISAMPLE);
    glDrawArrays(GL_TRIANGLES, 0, sector.vertexCount);
    glDisable(GL_MULTISAMPLE);

    // 解析到输出纹理
    glBindFramebuffer(GL_READ_FRAMEBUFFER, sector.msaaFbo);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, sector.resolveFbo);
    glBlitFramebuffer(0, 0, sector.width, sector.height,
                      0, 0, sector.width, sector.height,
                      GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
